import random
import re
from datetime import datetime

from flask import request, abort, current_app, make_response, jsonify, session

from info import sr, db
from info.lib.yuntongxun.sms import CCP
from info.models import User
from info.modules.passport import passport_blu
from info.utils.captcha.pic_captcha import captcha
from info.utils.response_code import RET, error_map

# 获取图片验证码
@passport_blu.route('/get_img_code')
def get_img_code():

    # 获取参数和图书案例是一样的，
    img_code_id = request.args.get('img_code_id')
    # 先获取在检验参数
    if not  img_code_id:
        return abort(403) # 403 拒绝访问，客户端错误

    # 生成图片的验证码
    img_name,img_code_text,img_code_bytes = captcha.generate_captcha()
    # 将图片的key 和验证文字保存到数据库中
    try:
        sr.set('img_code_id_' + img_code_id,img_code_text,ex=180) # redis 存储，键值对
    except BaseException as e:
        current_app.logger(e)
        return abort(500)  # 数据库错误，服务端
    # 返回验证码图片,要自定义响应对象，否则返回的就是一个图片二进制内容，会乱码
    # 创建和设置响应头
    response =make_response(img_code_bytes) # type: Response

    response.content_type = 'image/jpeg'

    return response

# 获取短信的验证码
@passport_blu.route('/get_sms_code',methods=['POST'])
def get_sms_code():

    # 获取参数,还是json 还是通过data 去取，不过时取出是解码的数据
    #  request.json 可以获取application/json 格式传过来的二进制数据，自动解码

    img_code_id = request.json.get('img_code_id')
    img_code = request.json.get('img_code')
    mobile = request.json.get('mobile')
    print(img_code, img_code_id, mobile)
    # 校验参数
    if not all([img_code_id,img_code,mobile]):
        return jsonify(errno=RET.PARAMERR,errmsg=error_map[RET.PARAMERR])

    # 校验手机号格式
    if not re.match(r'1[35789]\d{9}$',mobile):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])
    # 根据图片key 取出验证码的文字
    try:


        real_img_code = sr.get('img_code_id_' + img_code_id)  #### img_code_id_　少了一个＿


    except BaseException as e :
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])
    # 校验图片验证码
    if not real_img_code: # 两种可能：１．是过期了，２．key 错误　
        return jsonify(errno=RET.PARAMERR, errmsg='验证码已经过期')

    print(1111111111)

    if img_code.upper() != real_img_code: # 校验验证码是否一致,不区分大小写，－－－－－－注意
        # print(222222)


        # print(real_img_code.decode()) ###.decode()

        # print(333333333)
        return jsonify(errno=RET.PARAMERR, errmsg='验证码错误')
    # 若果　校验成功，发送短信
    # 生成４位随机的数字
    sms_code = '%04d' % random.randint(0,9999)
    current_app.logger.info('短信验证码为：%s' % sms_code)
    # res_code = CCP().send_template_sms(mobile,[sms_code,5],1)
    # if res_code == -1 : # 短信发送失败
    #     return jsonify(errno=RET.THIRDERR,errmsg=error_map[RET.THIRDERR])
    # # 将短信验证码保存到redis
    try:
        sr.set('sms_code_id_'+mobile,sms_code,ex=60)
        print(mobile, sms_code)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])
    print(555)

    # 将短信发送结果使用json 返回
    return jsonify(errno=RET.OK, errmsg=[RET.OK])

# 实现注册
@passport_blu.route('/register',methods=['POST'])
def register():

    # 获取参数　request.json 可以获取到applicayion/ison格式传来的数据，会自动解码
    mobile = request.json.get('mobile')
    password = request.json.get('password')
    sms_code = request.json.get('sms_code')
    # 检验参数
    if not all([mobile,password,sms_code]):
        return jsonify(errno=RET.PARAMERR,errmsg=error_map[RET.PARAMERR])

    # 校验手机号格式
    if not re.match(r'1[35678]\d{9}$',mobile):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 根据手机号取取出验证码文字
    try:
        real_sms_code = sr.get('sms_code_id_' + mobile)
    except BaseException as e :
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg=error_map[RET.DBERR])
    # 校验图片验证码

    if not real_sms_code: # 校验是否过期
        return jsonify(errno=RET.PARAMERR,errmsg='验证码已经过期')

    if sms_code != real_sms_code:
        return jsonify(errno=RET.PARAMERR, errmsg='验证码错误')

    # 将用户数据保存到数据库中
    user = User()
    user.mobile = mobile
    user.password = password # 使用计算属性password 对密码过程进行封装
    user.nick_name = mobile

    # 记录用户最后登录的时间
    user.last_login = datetime.now()

    # 将用户的信息保存到数据库中
    try:
        db.session.add(user)
        db.session.commit()
    except BaseException as e:
        db.session.rollback() # 设置回滚
        return jsonify(errno=RET.DBERR,errmsg=error_map[RET.DBERR])

    # 状态保持，免密码登录
    session['user_id'] = user.id
    return jsonify(errno=RET.OK,errmsg=error_map[RET.OK])

# 登录
@passport_blu.route('/login', methods=['POST'])
def login():
    # 获取参数
    mobile = request.json.get("mobile")
    password = request.json.get("password")
    # 校验参数
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 校验手机号格式
    if not re.match(r"1[35678]\d{9}$", mobile):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 根据手机号从数据库中取出用户模型
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    if not user:
        return jsonify(errno=RET.USERERR, errmsg=error_map[RET.USERERR])

    # 校验密码
    if not user.check_password(password):
        return jsonify(errno=RET.PWDERR, errmsg=error_map[RET.PWDERR])

    # 记录用户最后的登录时间
    user.last_login = datetime.now() # 在config 文件中１８行，添加自动提交的配置

    # 状态保持
    session["user_id"] = user.id

    # 将校验结果以json返回
    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])


# 退出登录
@passport_blu.route('/logout')
def logout():
    # 将用户信息从session 中删除，pop 可以设置默认值，当键值不存在时，不会报错，会返回默认值
    session.pop('user_id',None)

    # 将结果返回
    return jsonify(errno=RET.OK,errmsg=error_map[RET.OK])


